﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using XExcel.Validations;

namespace XExcel.Models
{
    [DebuggerDisplay("RowIndex = {RowIndex}, Cells = [{Cells}], Data = {Data}")]
    class NpoiRow<T> : IXRow<T> where T : new()
    {
        private T value;
        private List<IXCell> cells = new List<IXCell>();
        private List<ExcelError> errors = new List<ExcelError>();
        public IXSheet Sheet { get; }
        private static List<PropertyInfo> propertyInfos;

        public NpoiRow(int rowIndex, IXSheet<T> sheet)
        {
            RowIndex = rowIndex;
            Sheet = sheet;
        }

        public int RowIndex { get; }

        public IList<IXCell> Cells => cells.AsReadOnly();
        public IList<ExcelError> Errors => errors.AsReadOnly();

        public T Data => value;

        public TranferState State { get; private set; } = TranferState.Init;

        public void Add(IXCell cell)
        {
            cells.Add(cell);
        }

        public void Transfer(List<Mapper> convertors)
        {
            State = TranferState.Success;
            value = new T();
            foreach(var mapper in convertors)
            {
                var cell = Cells.FirstOrDefault(x => x.ColumnName == mapper.ColumnName);
                if(cell == null)
                {
                    continue;
                }
                var pi = PropertyInfos.FirstOrDefault(x => x.Name == mapper.PropertyName);
                if(pi == null)
                {
                    pi = PropertyInfos.FirstOrDefault(x => x.Name.Equals(mapper.PropertyName, StringComparison.CurrentCultureIgnoreCase));
                }
                try
                {
                    var val = mapper.Convertor != null ? mapper.Convertor.Invoke(cell) : cell.GetValueOrError(pi.PropertyType);
                    if(mapper.Validate != null)
                    {
                        if(!mapper.Validate.Test(val))
                        {
                            State = TranferState.Fail;
                            errors.Add(new ExcelError(this, mapper.ColumnName)
                            {
                                Message = mapper.Validate.Message
                            });
                        }
                    }
                    pi.SetValue(value, val);
                }
                catch(Exception ex)
                {
                    State = TranferState.Fail;
                    errors.Add(new ExcelError(this, mapper.ColumnName)
                    {
                        Message = "数据类型错误：" + ex.Message
                    });
                }
            }
        }

        static List<PropertyInfo> PropertyInfos => propertyInfos ?? (propertyInfos = typeof(T).GetProperties().Where(x => x.CanWrite).ToList());
    }
}